package com;
import java.util.ArrayList;

import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class OSMHandler extends DefaultHandler{
	
	/*This class defines a handler containing methods specifying what to do when the parser
	reads each attribute in the XMl file.*/
		
	//a Hashtable of all the nodes defined in the graph.
	public NodesinXML nodesinXML;
    private Node node;
    public static SimpleWeightedGraph<Node, DefaultWeightedEdge> graph;
    //a reference to the previous node parsed. initialised to null at start of file.
    private Node prev_node = null;
    //an ArrayList containing the IDs of all the nodes defined in a particular Way. 
	private ArrayList<String> nodesInWay = new ArrayList<String>();
	//a flag that when set to true means that the nodes in a particular Way can be added to the graph. 
	private boolean addwaytograph = false;
    
    public void startDocument () {
    	//create a new Hashtable.
    	nodesinXML = new NodesinXML();
    	//create a new undirected weighted graph.
    	graph = new SimpleWeightedGraph<Node, DefaultWeightedEdge>(DefaultWeightedEdge.class);
    }
    
    public void endDocument () {
    }

    public void startElement (String uri, String name, String qName, Attributes atts) throws SAXException{
    	if(qName.equals("node")){
    		//for every node defined, create a new Node containing its information.
        	node = new Node();
            node.lat = atts.getValue("lat");
            node.lon = atts.getValue("lon");
            node.id = atts.getValue("id");  
        return; 
        } else if(qName.equals("way")){
        return;
        } else if(qName.equals("nd")){
        	//for every node in the Way, add its ID to nodesInWay.
        	String node_id = atts.getValue("ref");
        	nodesInWay.add(node_id);
        return;
        } else if(qName.equals("tag")){
        	//if there is a tag "name" and its value is a street/road, then set the flag to true.
        	//reference: http://wiki.openstreetmap.org/wiki/Map_Features
        	String tagk = atts.getValue("k");
        	if (tagk.equals("highway")) {String tagv = atts.getValue("v");
        								if (tagv.indexOf("primary") != -1 || tagv.indexOf("secondary") != -1 || tagv.indexOf("tertiary") != -1
        								    || tagv.indexOf("residential") != -1 || tagv.indexOf("unclassified") != -1)
        								     {addwaytograph = true;}
                  						else {addwaytograph = false;}
        	} else {}
        	
        return;
        }
	
    }
    
    public void endElement (String uri, String name, String qName){
        if(qName.equals("way")){
        	//if the flag is set to true, then add all the nodes in the particular Way 
        	//to the graph (but only if they dont already exist) and create edges between them.
        	if (addwaytograph == true) {
        		for (String str : nodesInWay) {
  		  		Node node = nodesinXML.nodes.get(str);
  		  		try {if (!graph.containsVertex(node)) {graph.addVertex(node);} else {}
  		  			//if a node is the 1st one of a Way, then dont create any edges and move on.
  		  			//otherwise, create edge with previous node, update prev_node and move on. 
  		  			if (prev_node != null) {graph.addEdge(node, prev_node);
        									DefaultWeightedEdge edge = graph.getEdge(node, prev_node);
        									graph.setEdgeWeight(edge, DistBetwNodes.get_distance(node, prev_node));
        									prev_node = node;}
  		  			else {prev_node = node;}
  		  		} catch (NullPointerException e) {System.out.println(e);}}
        		
        		//once all nodes in the Way have been added, reset the values.
        		prev_node = null;
            	addwaytograph = false;
        	} else {}
        	//if flag is false then the Way is not a street so ignore and clear nodesInWay.
        	nodesInWay.clear();
        return;
        } else if(qName.equals("node")){
        	//at the end of a node definition, add the created Node to the Hashtable.
        	nodesinXML.addNode(node);
        return;
        } 
        
    }
    

    
   
    



    
    
    
    

	
	
	
	
}
